const std = @import("std");
const maxInt = std.math.maxInt;

const Direction = @import("direction.zig").Direction;


pub const Snake = struct {
	initial_length: u8 = 3,
	allocator: std.mem.Allocator = std.heap.page_allocator,
	_body: std.ArrayList([2]u8) = undefined,
	_current_direction: Direction = Direction{.up = true},


	pub fn init(self: *Snake, start_pos: [2]u8) !void {
		self._body = try std.ArrayList([2]u8)
				.initCapacity(self.allocator, self.initial_length);
		for (0..self.initial_length) |_| {
			try self._body.append(start_pos);
		}
	}


	pub fn deinit(self: *Snake) void {
		self._body.deinit();
	}


	pub fn get_cells(self: *Snake) [][2]u8 {
		return self._body.items;
	}


	pub fn get_size(self: *Snake) usize {
		return self._body.items.len;
	}


	pub fn get_head(self: *Snake) ?[2]u8 {
		if (self._body.items.len > 0) {
			return self._body.items[0];
		}
		return null;
	}


	pub fn move(self: *Snake, move_direction: Direction) !void {
		const head: [2]u8 = self.get_head() orelse return;

		var valid_move: bool = true;
		if (!move_direction.any()) {
			valid_move = false;
		} else if (self._body.items.len > 1) {
			const direction_2nd_cell: Direction = Direction.as_direction(
					self._body.items[0], self._body.items[1]);
			if (move_direction.eq(direction_2nd_cell)) {
				valid_move = false;
			}
		}

		if (valid_move) {
			self._current_direction = move_direction;
		}

		var new_pos: [2]u8 = head;
		if (self._current_direction.right) {
			new_pos[0] +%= 1;
		} else if (self._current_direction.left) {
			new_pos[0] -%= 1;
		} else if (self._current_direction.up) {
			new_pos[1] -%= 1;
		} else if (self._current_direction.down) {
			new_pos[1] +%= 1;
		}

		_ = self._body.pop();
		try self._body.insert(0, new_pos);
	}


	pub fn add_cell(self: *Snake) !void {
		const last_pos: [2]u8 = self._body.items[self._body.items.len - 1];
		try self._body.append(last_pos);
	}
};
